package aop;

import java.util.*;
import java.lang.reflect.*;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;


public class Bean {
    private String id; //bean 的id或者className
    private Class<?> clazz;
    private Object instance;

    public Bean(String id, Class<?> clazz) {
        this.id = id;
        this.clazz = clazz;
    }

    // Method interceptor for bean proxy class.
    //代理bean的获取
    private static class BeanProxyInterceptor implements MethodInterceptor {
        DefaultBeanFactory beanFactory;
        BeanAspects beanAspects;

        public BeanProxyInterceptor(DefaultBeanFactory beanFactory, BeanAspects beanAspects) {
            this.beanFactory = beanFactory;
            this.beanAspects = beanAspects;
        }

        private void invokeAspectMethod(String aspectBeanId, Method method) throws Exception {
            if (Modifier.isStatic(method.getModifiers())) {//静态方法
                method.invoke(null);
            } else {//非静态方法，无参构造
                method.invoke(beanFactory.getBean(aspectBeanId));
            }
        }

        @Override
        public Object intercept(Object obj, Method method, Object[] args,
                                MethodProxy proxy) throws Throwable {
            Map<String, BeanAspects.AspectMethods> aspects = beanAspects.pointCutAspects.get(method);
            if (aspects == null) {
                // No aspect for this method.
                return proxy.invokeSuper(obj, args);
            }

            //前置通知方法
            for (Map.Entry<String, BeanAspects.AspectMethods> entry : aspects.entrySet()) {
                String aspectBeanId = entry.getKey();
                BeanAspects.AspectMethods aspectMethods = entry.getValue();
                // Invoke aspect "before" methods.
                for (Method m : aspectMethods.beforeMethods) {
                    invokeAspectMethod(aspectBeanId, m);
                }
            }

            // Invoke the original method.
            Object re = proxy.invokeSuper(obj, args);
            //后置通知方法
            for (Map.Entry<String, BeanAspects.AspectMethods> entry : aspects.entrySet()) {
                String aspectBeanId = entry.getKey();
                BeanAspects.AspectMethods aspectMethods = entry.getValue();
                // Invoke aspect "after" methods.
                for (Method m : aspectMethods.afterMethods) {
                    invokeAspectMethod(aspectBeanId, m);
                }
            }

            return re;
        }
    }

    public Object getInstance(DefaultBeanFactory beanFactory) throws Exception {
        //如果有实例化就返回
        if (this.instance != null) {
            return this.instance;
        }

        synchronized (this) {
            if (this.instance != null) {
                return this.instance;
            }

            //
            if (!beanFactory.aops.containsKey(id)) {
                // 如果bean工厂不存在这个beanid，通过反射返回一个简单类
                this.instance = (Object) clazz.getConstructor(new Class[]{}).newInstance();
            } else {
                //获取切面
                BeanAspects beanAspects = beanFactory.aops.get(id);
                // Create proxy class instance.
                Enhancer eh = new Enhancer();
                eh.setSuperclass(clazz);
                eh.setCallback(new BeanProxyInterceptor(beanFactory, beanAspects));
                //返回代理类
                this.instance = eh.create();
            }


            return this.instance;
        }
    }
}
